use crate::key_manager::algorithm::factory::algorithm_factory::KeyAlgorithm;
use crate::key_manager::error::KeyManagerError;
use crate::register_algorithm;
use anyhow::anyhow;
use anyhow::{Context, Result};
use openssl::ec::EcKey;
use openssl::pkey::{PKey, Private, Public};
use openssl::sign::{Signer, Verifier};

#[derive(Debug)]
pub struct EcAlgorithm {
    _curve: String,
}

impl KeyAlgorithm for EcAlgorithm {
    fn derive_public(&self, private: &Vec<u8>) -> Result<Vec<u8>, KeyManagerError> {
        let ec_key = EcKey::private_key_from_der(private)?;
        ec_key
            .public_key_to_der()
            .context("Failed to derive public key")
            .map_err(|e| KeyManagerError::new(format!("Failed to derive public key: {}", e)))
    }

    fn sign(&self, private: &PKey<Private>, data: Vec<u8>) -> Result<Vec<u8>, KeyManagerError> {
        let mut signer = Signer::new_without_digest(private)?;
        signer
            .sign_oneshot_to_vec(data.clone().as_slice())
            .context("ECDSA signing failed")
            .map_err(|e| KeyManagerError::new(format!("ECDSA signing failed: {}", e)))
    }

    fn verify(
        &self,
        public: &PKey<Public>,
        data: Vec<u8>,
        sig: Vec<u8>,
    ) -> Result<bool, KeyManagerError> {
        let mut verifier = Verifier::new_without_digest(public)?;
        verifier
            .verify_oneshot(sig.clone().as_slice(), data.clone().as_slice())
            .context("ECDSA verification failed")
            .map_err(|e| KeyManagerError::new(format!("ECDSA verification failed: {}", e)))
    }
}

register_algorithm!("ec", |args: &[&str]| -> Result<Box<dyn KeyAlgorithm>> {
    let curve = args
        .first()
        .ok_or(KeyManagerError::new(
            "EC algorithm requires curve parameter (e.g. 'ec prime256v1')",
        ))?
        .to_string();

    if !["secp256k1", "prime256v1"].contains(&&*curve) {
        return Err(anyhow!("SM2 algorithm does not accept parameters"));
    }

    Ok(Box::new(EcAlgorithm { _curve: curve }))
});
